package dpkg

import (
	"fmt"
	"os/exec"
	"strings"

	"gitee.com/liumou_site/gf"
	"gitee.com/liumou_site/logger"
	"github.com/spf13/cast"
)

// GetPackageInfo 通过解析 `dpkg -I` 命令的输出，获取指定 `.deb` 文件的软件包信息。
// 该函数会解析软件包的架构、依赖、包名、版本和维护者等信息，并将其存储在 `DebPackageInfo` 结构体中。
//
// 参数:
//   - filename: 要解析的 `.deb` 文件的路径。
//
// 返回值:
//   - api.PackageInfo: 通过实例变量访问。
//   - error: 如果解析过程中发生错误，返回相应的错误信息；否则返回 nil。
func (api *DpkgStruct) GetPackageInfo(filename string) error {
	_, err := exec.LookPath("dpkg")
	if err != nil {
		return err
	}
	f := gf.NewFile(filename)
	f.IsFile()
	if !f.IsFiles {
		return fmt.Errorf("这不是一个文件: %s", filename)
	}
	// 运行 `dpkg -I` 命令获取软件包信息，并将输出存储在 `api.Sudo.Strings` 中
	api.Sudo.Realtime = false
	api.Sudo.RunShell("dpkg -I " + filename)
	// 初始化 `api.PackageInfo` 结构体，并将其赋值给 `api.PackageInfo`
	api.PackageInfo = new(DebPackageInfo)
	api.PackageInfo.Filename = filename
	api.PackageInfo.MD5sum = gf.GetFileMd5(filename)

	// 解析 `dpkg -I` 命令的输出，提取软件包的架构、依赖、包名、版本和维护者等信息
	for _, line := range strings.Split(api.Sudo.Strings, "\n") {
		if strings.Contains(line, "Architecture") {
			api.PackageInfo.Architecture = strings.Split(line, ":")[1]
			continue
		}
		if strings.Contains(line, "Depends") {
			api.PackageInfo.Depends = strings.Split(line, ",")
			continue
		}
		if strings.Contains(line, "Package") {
			api.PackageInfo.Package = strings.Split(line, ":")[1]
			continue
		}
		if strings.Contains(line, "Version") {
			api.PackageInfo.Version = strings.Split(line, ":")[1]
			continue
		}
		if strings.Contains(line, "Maintainer") {
			api.PackageInfo.Maintainer = strings.Split(line, ":")[1]
			continue
		}
		if strings.Contains(line, "Description") {
			api.PackageInfo.Description = strings.Split(line, ":")[1]
			continue
		}
		if strings.Contains(line, "Homepage") {
			api.PackageInfo.Homepage = strings.Split(line, ":")[1]
			continue
		}
		if strings.Contains(line, "Installed-Size") {
			api.PackageInfo.InstalledSize = cast.ToInt(strings.Split(line, ":")[1])
			continue
		}
		if strings.Contains(line, "Priority") {
			api.PackageInfo.Priority = strings.Split(line, ":")[1]
			continue
		}
		// 获取分类Section
		if strings.Contains(line, "Section") {
			api.PackageInfo.Section = strings.Split(line, ":")[1]
		}

	}
	if api.PackageInfo.Package == "" || api.PackageInfo.Version == "" || api.PackageInfo.Architecture == "" {
		return fmt.Errorf("无法获取包信息,请检查这个文件是否为标准文件: %s", filename)
	}
	return nil
}

// GetPackageInfoList 遍历给定的文件列表，获取每个文件的包信息，并将其添加到 PackageInfoList 中。
// 如果获取某个文件的包信息时发生错误，会记录错误日志并继续处理下一个文件。
//
// 参数:
//   - fileList: 包含文件路径的字符串切片，每个文件路径用于获取对应的包信息。
//
// 返回值:
//   - 无
//   - 可通过 api.PackageInfoList 访问结果数据
func (api *DpkgStruct) GetPackageInfoList(fileList []string) {
	// 遍历文件列表，逐个获取包信息
	for _, file := range fileList {
		// 获取单个文件的包信息
		err := api.GetPackageInfo(file)
		if err != nil {
			// 如果获取包信息失败，记录错误日志并继续处理下一个文件
			logger.Error("GetPackageInfoList error: %v", err)
			continue
		}
		// 将成功获取的包信息添加到 PackageInfoList 中
		api.PackageInfoList = append(api.PackageInfoList, *api.PackageInfo)
	}
}

func (api *DpkgStruct) GetPackageResultInstalled() ([]DpkgListResult, error) {
	// 检查 dpkg 命令是否存在
	_, err := exec.LookPath("dpkg")
	if err != nil {
		return nil, err
	}

	// 执行 dpkg -l 命令获取已安装包的信息
	api.Sudo.Realtime = false
	api.Sudo.RunShell("dpkg -l")
	if api.Sudo.Err != nil {
		return nil, err
	}

	// 调用内部函数解析输出
	results := ParseDpkgOutput(api.Sudo.Strings)
	return results, nil
}

// ParseDpkgOutput 用于解析 dpkg -l 命令的输出
func ParseDpkgOutput(output string) []DpkgListResult {
	// 初始化结果切片
	var results []DpkgListResult

	// 解析 dpkg -l 命令的输出
	lines := strings.Split(output, "\n")
	for _, line := range lines {
		// 跳过空行
		if line == "" || strings.TrimSpace(line) == "" {
			continue
		}

		// 跳过表头行（更严格的匹配逻辑）
		if strings.HasPrefix(line, "Desired") || strings.HasPrefix(line, "++-") || strings.HasPrefix(line, "||/") {
			continue
		}

		// 解析每行数据
		fields := strings.Fields(line)
		if len(fields) >= 5 {
			result := DpkgListResult{
				Status:       fields[0],
				Name:         fields[1],
				Version:      fields[2],
				Architecture: fields[3],
				Description:  strings.Join(fields[4:], " "),
			}
			results = append(results, result)
		}
	}

	return results
}
